package cn.lg.soar.common.data.tree;

import cn.lg.soar.common.util.data.DataUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 树形数据（同时兼具 children 和 parentId）
 * @author luguoxiang
 * @param <ID>
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface ITreeData<ID, T extends ITreeData<ID, T>> extends ITreeSource<ID>, ITreeResult<T> {

    /**
     * 将list数据转为树形数据
     * @param list
     * @param parentId
     * @param <ID>
     * @param <T>
     * @return
     */
    static <ID, T extends ITreeData<ID, T>> List<T> toTree(List<T> list, ID parentId) {
        // map 方式（性能最好）
        Map<ID, List<T>> map = list.stream().collect(Collectors.groupingBy(T::getParentId));
        for (T t : list) {
            t.setChildren(map.get(t.getId()));
        }
        return map.get(parentId);

        // filter 方式（性能较好）
        /*List<T> rs = new ArrayList<>();
        for (T t : list) {
            if (Objects.equals(parentId, t.getParentId())) {
                rs.add(t);
            }
            t.setChildren(list.stream().filter(x -> Objects.equals(x.getParentId(), t.getId())).collect(Collectors.toList()));
        }
        return rs;*/

        // 递归方式（性能差）
        /*List<T> rs = new ArrayList<>();
        for (T t : list) {
            if (!Objects.equals(parentId, t.getParentId())) {
                continue;
            }
            List<T> ts = valueOf(list, t.getId());
            if (!ts.isEmpty()) {
                t.setChildren(ts);
            }
            rs.add(t);
        }
        return rs;*/
    }

    /**
     * 树形数据扁平化
     * @param tree 源数据
     * @param <ID> id类型
     * @param <S> 源数据类型
     * @param <R> 树形数据类型
     * @return
     */
    static <ID, T extends ITreeData<ID, T>> List<T> toList(List<T> tree) {
        List<T> list = new ArrayList<>(128);
        toList(tree, list);
        return list;
    }

    /**
     * 树形数据扁平化（建议使用 valueOf 函数）
     * @param tree 树数据
     * @param list 扁平数据
     * @param <ID>
     * @param <R>
     * @param <S>
     */
    static <ID, T extends ITreeData<ID, T>> void toList(List<T> tree, List<T> list) {
        for (T t : tree) {
            list.add(t);
            List<T> children = t.getChildren();
            if (DataUtil.isValuable(children)) {
                toList(children, list);
            }
        }
    }
}
